package com.favccxx.search.application;

import com.favccxx.search.domain.datamapper.*;
import com.favccxx.search.domain.datamapper.horizontal.HorizontalMapper;
import com.favccxx.search.domain.datamapper.vertical.VerticalMapper;
import com.favccxx.search.domain.datamapper.vertical.VerticalMapperUtil;
import com.favccxx.search.infrastructure.util.jackson.JacksonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author favccxx
 * @date 5/13/2020 5:27 PM
 */
@Slf4j
@Service
public class DataMapperService {

    @Autowired
    MapperService mapperService;

    public List<DataMapper> findAll() {
        return mapperService.findAll();
    }

    /**
     * Get concept model mapper by concept model id
     *
     * @param conceptModelId
     * @return
     */
    public DataMapper findByConceptModelId(String conceptModelId) {
        return mapperService.findByConceptModelId(conceptModelId);
    }

    /**
     * Get concept model mapper by project id and concept model code
     *
     * @param projectId
     * @param conceptModelCode
     * @return
     */
    public DataMapper findByProjectIdAndConceptModelCode(String projectId, String conceptModelCode) {
        return mapperService.findByProjectIdAndConceptModelCode(projectId, conceptModelCode);
    }

    /**
     * Save horizontal table mapper
     *
     * @param horizontalMapper
     */
    public void saveHorizontalMapper(DataMapper horizontalMapper) {
        String sql = generateMapperSql(horizontalMapper);
        horizontalMapper.setQuerySql(sql);
        mapperService.saveDataMapper(horizontalMapper);
    }

    /**
     * Save vertical table mapper
     *
     * @param verticalMapper
     */
    public void saveVerticalMapper(DataMapper verticalMapper) {
        mapperService.saveDataMapper(verticalMapper);
    }


    /**
     * Generate Horizontal table mapper sql
     *
     * @param horizontalMapper
     * @return
     */
    public String generateMapperSql(DataMapper horizontalMapper) {
        String sql = "";
        // for single table map sql
        if (StringUtils.isBlank(horizontalMapper.getMapperCondition())) {
            for (Object obj : horizontalMapper.getMapperFields()) {
                DataSetMapper mapper = JacksonUtil.fromJson(JacksonUtil.toJsonString(obj), DataSetMapper.class);
                sql = buildSingleSql(mapper);
                return sql;
            }
        }

        // work for multiple table map sql
        sql = buildMultiSql(horizontalMapper.getMapperFields()) + horizontalMapper.getMapperCondition();
        log.info("ful sql: " + sql);
        return sql;
    }

    /**
     * Generate vertical mapper sql
     *
     * @param verticalMapper
     * @return
     */
    public String generateVerticalMapperSql(DataMapper verticalMapper) {
        // Single vertical table mapper
        return VerticalMapperUtil.buildVerticalMapperSql(verticalMapper);
    }


    /**
     * For single mapper raw table
     *
     * @param mapper
     * @return
     */
    private String buildSingleSql(DataSetMapper mapper) {
        StringBuffer sb = new StringBuffer();
        sb.append("Select ");
        String dataSourceCode = mapper.getDataSourceCode();
        String dataSetCode = mapper.getDataSetCode();
        List<FieldMapper> mapperList = mapper.getFiledMapperList();
        for (int i = 0; i < mapperList.size(); i++) {
            FieldMapper fieldMapper = mapperList.get(i);
            sb.append("\"").append(dataSourceCode).append("\".\"").append(dataSetCode).append("\".\"").append(fieldMapper.getDataSetFieldCode()).append("\" as ").append(fieldMapper.getEntityFiledCode());

            if (i + 1 < mapperList.size()) {
                sb.append(", ");
            }
        }

        sb.append(" From \"").append(dataSourceCode).append("\".\"").append(dataSetCode).append("\"");
        log.info("SQL: " + sb.toString());
        return sb.toString();
    }

    /**
     * Build search sql for multiple raw table
     *
     * @param dataSetMappers
     * @return
     */
    private String buildMultiSql(List<DataSetMapper> dataSetMappers) {
        if (dataSetMappers == null || dataSetMappers.size() == 0) {
            return "";
        }

        if (dataSetMappers.size() == 1) {
            return buildSingleSql(dataSetMappers.get(0));
        }

        StringBuffer sb = new StringBuffer();
        sb.append("Select ");

        for (int i = 0; i < dataSetMappers.size(); i++) {
            DataSetMapper mapper = dataSetMappers.get(i);

            String dataSourceCode = mapper.getDataSourceCode();
            String dataSetCode = mapper.getDataSetCode();
            for (FieldMapper fieldMapper : mapper.getFiledMapperList()) {
                sb.append(dataSourceCode).append(".").append(dataSetCode).append(".").append(fieldMapper.getDataSetFieldCode()).append(" as ").append(fieldMapper.getEntityFiledCode()).append(", ");
            }
        }

        String startSql = sb.toString();
        startSql = startSql.substring(0, startSql.length() - 2);
        log.info("start sql: " + startSql);


        StringBuffer endSb = new StringBuffer();
        endSb.append(startSql).append(" From ");
        for (int i = 0; i < dataSetMappers.size(); i++) {
            DataSetMapper mapper = dataSetMappers.get(i);
            endSb.append(mapper.getDataSourceCode()).append(mapper.getDataSetCode());

            if (i < dataSetMappers.size()) {
                sb.append(",");
            }
        }
        log.info("endSql: " + endSb.toString());


        return endSb.toString();

    }
}
